在分析前,我們要討論的是「具體要分析什麼」,這是每次分析資料以前,要先問的問題。當然你也可以先做個EDA觀察資料,但在一般實務情況下,都會先訂框架。
我先拋磚引玉,丟幾個問題。不管資料內容長怎樣,先問:某個人、某些人講的話,有什麼會是重點?一般人講話,我們可能會看他有沒有慣用的講話模式,例如有人愛罵髒話,有人愛用成語,至於總統,我們關注他們的身份,既然他們代表國家、手握權力,那我們可能想知道他們話語中,跟國家有關的詞彙,同時也想知道他們如何運用權力,具體來說就是會如何談論哪些政策,或者說施政重點。
走到這步,其實就已經不錯了,我們知道我們關心國家與施政重點。當資料夠豐富,我們可以看得更細緻,例如關心國家以外,總統也有外交權力,那要怎麼跟其他國家互動?要怎麼看待兩岸關係?至於施政重點,會看重哪些面向?怎麼談論自己重視的價值?譬如說我們可以猜測,有人拼經濟、有人護安全,有人兩個都要,台灣安群、人民有錢。
知道要看的焦點之後,下一步就是方法了,我們可以怎麼看?哪些叫做重點?應該說,要怎麼量化重點?
很明顯的,前面講過看用頻率看熱門詞彙,絕對會是最基本的辦法,另外關鍵詞彙,包含
information gain、chi statistics 或者是 tf-idf 都可以拿來合適的指標。
除此之外,我們不只關注一個總統,我們關注很多總統(至少有四位),所以可以將不同總統的維度納入分析,當然,也可以以年份比較。既然以年份或總統來比較,那我們除了看詞頻以外,想要掌握某位總統講話的重點,有什麼方法呢?什麼叫做他關心的議題?
有一種作法是從分析方法來看,逐一探討可以派上用場的工具,例如想到主題模型,他是一種拿來將文本分出大方向的好工具,但他在此並不適用,為什麼?因為我們沒有很多篇文章,只有少少的幾篇文章,跟手握數百篇的應用情境不一樣。不過,這種從方法來看的做法最好在後面一點再拿來用,前面還是像上面的做法,先抓目標、再切維度,接著找指標量化,最後這一步才會落地到分析方法。
既然要抓到重點,那利用詞彙共現是個不錯的方式,因爲他的其中一個看法就是「要不一起出現、要不都不出現」(pairwise
correlation),所以我們可以用這招。此外,我們前面有提到國家的對外關係,那或許我們也能衡量提到某些國家的態度。通常這可以用情感分析,不過我認為此處並不適合。為什麼呢?因為總統能講的話篇幅有限,而且文章數太少,這種用數的還比較快,當資料量很大、跨越很多年,再來用情感分析衡量比較好,畢竟情感分析的準確性沒那麼高,樣本小的時候個人就不會想用了。我們倒是可以考慮用詞嵌入模型喔!因為裡面有空間分佈的概念,可以看台灣和美國、台灣和中國等相對位置,也能找相似詞。
以上就是分析前的一系列思路。接著我們進入程式碼部分。
library(tidyverse)
library(tidytext)
library(widyr)
library(ggraph)
df_speech_seg_unnest <- read_rds("data/國慶演說/df_speech_seg_unnest.rds")
df_stopwords <- read_table("data/df_stopword.txt", col_names = F) %>%
rename(id = 1, text_segment = 2) %>% select(text_segment)
df_year_word_count <- df_speech_seg_unnest %>% count(year_full, year, president, text_segment, text_POS)
df_year_word_count %>% head(10)
## # A tibble: 10 × 6
## year_full year president text_segment text_POS n
## <dbl> <chr> <chr> <chr> <chr> <int>
## 1 1997 八十六 李登輝 、 Puncuation 8
## 2 1997 八十六 李登輝 。 Puncuation 10
## 3 1997 八十六 李登輝 「 Puncuation 2
## 4 1997 八十六 李登輝 」 Puncuation 2
## 5 1997 八十六 李登輝 一再 Adverb 1
## 6 1997 八十六 李登輝 一定 Adverb 1
## 7 1997 八十六 李登輝 上 Noun 5
## 8 1997 八十六 李登輝 下 Noun 1
## 9 1997 八十六 李登輝 不但 Conjunction 1
## 10 1997 八十六 李登輝 不斷 Adverb 1
### 2023年
df_year_word_count %>% filter(year_full == 2023) %>%
arrange(desc(n)) %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
anti_join(df_stopwords) %>%
head(20)
## # A tibble: 20 × 6
## year_full year president text_segment text_POS n
## <dbl> <chr> <chr> <chr> <chr> <int>
## 1 2023 一一二 蔡english 我們 Noun 51
## 2 2023 一一二 蔡english 臺灣 Noun 39
## 3 2023 一一二 蔡english 民主 Noun 20
## 4 2023 一一二 蔡english 世界 Noun 14
## 5 2023 一一二 蔡english 和平 Verb 14
## 6 2023 一一二 蔡english 國家 Noun 13
## 7 2023 一一二 蔡english 穩定 Verb 11
## 8 2023 一一二 蔡english 全球 Noun 10
## 9 2023 一一二 蔡english 兩岸 Noun 10
## 10 2023 一一二 蔡english 國際 Noun 10
## 11 2023 一一二 蔡english 已經 Adverb 8
## 12 2023 一一二 蔡english 感謝 Verb 8
## 13 2023 一一二 蔡english 前進 Verb 7
## 14 2023 一一二 蔡english 基礎 Noun 7
## 15 2023 一一二 蔡english 守護 Verb 7
## 16 2023 一一二 蔡english 成為 Verb 7
## 17 2023 一一二 蔡english 中華民國 Noun 6
## 18 2023 一一二 蔡english 區域 Noun 6
## 19 2023 一一二 蔡english 發展 Verb 6
## 20 2023 一一二 蔡english 維持 Verb 6
### 中華民國、台灣、美國、中國
df_year_word_count %>% filter(str_detect(text_segment, "中華|民國|臺灣")) %>%
count(text_segment) %>% head(10)
## # A tibble: 10 × 2
## text_segment n
## <chr> <int>
## 1 中華 9
## 2 中華民國 27
## 3 中華民族 6
## 4 民國 4
## 5 民國黨 1
## 6 臺灣 26
## 7 臺灣人 8
## 8 臺灣人樂 1
## 9 臺灣海峽 3
## 10 臺灣版 1
### 中華民國與台灣
df_president_roc <- df_year_word_count %>% filter(str_detect(text_segment, "中華|民國|臺灣")) %>%
filter(!str_detect(text_segment, "民國黨")) %>%
filter(text_segment != "民國") %>%
mutate(text_type = if_else(str_detect(text_segment, "中華|民國"), "中華民國", "臺灣")) %>%
group_by(president, text_type) %>%
summarise(n = sum(n))
df_president_roc
## # A tibble: 8 × 3
## # Groups: president [4]
## president text_type n
## <chr> <chr> <int>
## 1 李登輝 中華民國 14
## 2 李登輝 臺灣 5
## 3 蔡english 中華民國 49
## 4 蔡english 臺灣 330
## 5 陳水扁 中華民國 38
## 6 陳水扁 臺灣 285
## 7 馬英九 中華民國 121
## 8 馬英九 臺灣 252
df_president_year_roc <- df_year_word_count %>% filter(str_detect(text_segment, "中華|民國|臺灣")) %>%
filter(!str_detect(text_segment, "民國黨")) %>%
filter(text_segment != "民國") %>%
filter(text_segment != "臺灣海峽") %>%
mutate(text_type = if_else(str_detect(text_segment, "中華|民國"), "中華民國", "臺灣")) %>%
group_by(year_full, text_type) %>%
summarise(n = sum(n))
df_president_year_roc
## # A tibble: 53 × 3
## # Groups: year_full [27]
## year_full text_type n
## <dbl> <chr> <int>
## 1 1997 中華民國 4
## 2 1997 臺灣 1
## 3 1998 中華民國 5
## 4 1999 中華民國 5
## 5 1999 臺灣 4
## 6 2000 中華民國 7
## 7 2000 臺灣 8
## 8 2001 中華民國 3
## 9 2001 臺灣 12
## 10 2002 中華民國 4
## # ℹ 43 more rows
### 兩岸與美國
df_year_word_count %>% filter(str_detect(text_segment, "中共|兩岸|中國|美國|大陸|日本|北京|華府|華盛頓|白宮")) %>% count(text_segment)
## # A tibble: 10 × 2
## text_segment n
## <chr> <int>
## 1 中共 6
## 2 中國 17
## 3 中國人 2
## 4 兩岸 24
## 5 北京 7
## 6 大陸 12
## 7 日本 12
## 8 美國 15
## 9 美國人 1
## 10 華府 1
df_president_foreign <- df_year_word_count %>% filter(str_detect(text_segment, "中共|兩岸|中國|北京|美國|華府")) %>%
mutate(text_type = if_else(str_detect(text_segment, "中共|兩岸|中國|大陸|北京"), "中國", "美國")) %>%
group_by(president, text_type) %>%
summarise(n = sum(n))
df_president_year_foreign <- df_year_word_count %>% filter(str_detect(text_segment, "中共|兩岸|中國|北京|美國|華府")) %>%
mutate(text_type = if_else(str_detect(text_segment, "中共|兩岸|中國|大陸|北京"), "中國", "美國")) %>%
group_by(year_full, text_type) %>%
summarise(n = sum(n))
### 熱門詞彙 - year
df_year_word_top <- df_year_word_count %>% group_by(year_full) %>%
arrange(year_full, desc(n)) %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
anti_join(df_stopwords) %>%
mutate(rn = row_number()) %>%
filter(rn <= 10) %>%
ungroup()
df_year_word_top_wide <- df_year_word_top %>%
select(-text_POS, -n) %>%
pivot_wider(names_from = rn, values_from = text_segment)
df_year_word_top_wide
## # A tibble: 27 × 13
## year_full year president `1` `2` `3` `4` `5` `6` `7` `8` `9` `10`
## <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 1997 八十六 李登輝 我們 發展 國家 社會 中華民國 兩岸 自由 世界 基礎 成就
## 2 1998 八十七 李登輝 國家 我們 中華民國 繁榮 奮鬥 民主 發展 社會 世界 世紀
## 3 1999 八十八 李登輝 我們 國家 社會 國際 中華民國 兩岸 家園 方面 民眾 安全
## 4 2000 八十九 陳水扁 我們 政府 臺灣 中華民國 兩岸 和平 安全 世界 國家 提升
## 5 2001 九十 陳水扁 政府 臺灣 兩岸 經濟 我們 推動 民主 世紀 和平 國際
## 6 2002 九十一 陳水扁 我們 改革 臺灣 國家 積極 國際 政黨 民主 面對 信心
## 7 2003 九十二 陳水扁 臺灣 改革 我們 民主 經濟 相信 過去 政府 政治 今年
## 8 2004 九十三 陳水扁 臺灣 兩岸 國際 我們 共同 應該 阿扁 和平 發展 社會
## 9 2005 九十四 陳水扁 臺灣 政府 改革 我們 社會 國家 經濟 退休 金融 改革
## 10 2006 九十五 陳水扁 臺灣 國家 我們 民主 自由 過去 司法 政府 中國 政治
## # ℹ 17 more rows
### tf-idf - year
df_year_word_tfidf <- df_year_word_count %>% group_by(year_full) %>%
arrange(year_full, desc(n)) %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
group_by(year_full, year, president, text_segment) %>%
arrange(desc(n)) %>% filter(row_number() == 1) %>%
filter(!text_segment %in% c("2006年","九十七年","一百","一向","七十二","(一)","(三)", "三十", "六十")) %>%
anti_join(df_stopwords) %>% ungroup() %>%
bind_tf_idf(text_segment, year_full, n)
df_year_word_tfidf_top <- df_year_word_tfidf %>% group_by(year_full) %>%
filter(n > 2) %>%
arrange(desc(tf_idf)) %>%
mutate(rn = row_number()) %>%
filter(rn <= 10) %>% ungroup() %>%
arrange(year_full, rn)
df_year_word_tfidf_top_wide <- df_year_word_tfidf_top %>%
select(year_full, president, text_segment, rn) %>%
pivot_wider(names_from = rn, values_from = text_segment)
df_year_word_tfidf_top_wide
## # A tibble: 27 × 12
## year_full president `1` `2` `3` `4` `5` `6` `7` `8` `9` `10`
## <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 1997 李登輝 理想 成就 繁榮 兩岸 歷史 自由 世界 基礎 我們 發展
## 2 1998 李登輝 奮鬥 繁榮 國家 我們 中華民國 民主 發展 社會 <NA> <NA>
## 3 1999 李登輝 登輝 家園 發生 發揮 女士 方面 重建 事實 關懷 工作
## 4 2000 陳水扁 政權 潮流 利益 世紀 威權 兩千三百萬 方面 提升 安全 全體
## 5 2001 陳水扁 經發會 賄選 九一一 選舉 世紀 事件 恐怖 重建 朝野 和解
## 6 2002 陳水扁 阿扁 道路 利益 金融 改革 方面 信心 積極 政黨 代表
## 7 2003 陳水扁 雲門 黑金 掃除 景氣 伙伴 必然 曾經 最後 憲政 相信
## 8 2004 陳水扁 阿扁 故事 奧運 寫下 五二○ 台海 應該 兩千三百萬 聯合國 族群
## 9 2005 陳水扁 替代率 退休 金改 不當 黨產 利率 黨政軍 所得 相關 優惠
## 10 2006 陳水扁 貪腐 司法 體制 八月份 案件 認同 分歧 加油 中部 台海
## # ℹ 17 more rows
### 熱門詞彙 - president
df_president_word_top <- df_year_word_count %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
anti_join(df_stopwords) %>%
group_by(president, text_segment) %>%
summarise(n = sum(n)) %>%
arrange(president, desc(n)) %>%
mutate(rn = row_number()) %>%
filter(rn <= 10) %>%
ungroup()
df_president_word_top_wide <- df_president_word_top %>%
select(president, text_segment, rn) %>%
pivot_wider(names_from = rn, values_from = text_segment)
df_president_word_top_wide
## # A tibble: 4 × 11
## president `1` `2` `3` `4` `5` `6` `7` `8` `9` `10`
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 李登輝 我們 國家 社會 民主 發展 中華民國 兩岸 國際 繁榮 經濟
## 2 蔡english 我們 臺灣 國家 民主 經濟 世界 國際 社會 兩岸 發展
## 3 陳水扁 臺灣 我們 政府 國家 民主 改革 經濟 兩岸 社會 國際
## 4 馬英九 我們 臺灣 經濟 兩岸 中華民國 政府 國際 民主 國家 社會
### tf-idf - year
df_president_word_tfidf <- df_year_word_count %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
anti_join(df_stopwords) %>%
group_by(president, text_segment) %>%
summarise(n = sum(n)) %>%
arrange(president, desc(n)) %>%
# summarise(n = sum(n)) %>%
filter(!text_segment %in% c("2006年","九十七年","一百","一向","七十二","(一)","(三)", "三十", "六十")) %>%
anti_join(df_stopwords) %>% ungroup() %>%
bind_tf_idf(text_segment, president, n)
df_president_word_tfidf_top <- df_president_word_tfidf %>% group_by(president) %>%
filter(n > 2) %>%
arrange(desc(tf_idf)) %>%
mutate(rn = row_number()) %>%
filter(rn <= 10) %>% ungroup() %>%
arrange(president, rn)
df_president_word_tfidf_top_wide <- df_president_word_tfidf_top %>%
select(president, president, text_segment, rn) %>%
pivot_wider(names_from = rn, values_from = text_segment)
df_president_word_tfidf_top_wide
## # A tibble: 4 × 11
## president `1` `2` `3` `4` `5` `6` `7` `8` `9` `10`
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 李登輝 兄弟 登輝 父老 建國 熱烈 紀元 統一 理想 開創 世紀
## 2 蔡english 現場 國造 變局 印太 好朋友 守護 世代 毒品 重組 全球
## 3 陳水扁 阿扁 投票 名義 台海 輪替 政黨 美元 韓國 黑金 伙伴
## 4 馬英九 協議 鄉親 英九 簽訂 協定 簽證 閣下 活路 今年 全球
### 計算 correlation
word_cors_tsai <- df_speech_seg_unnest %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
filter(president == "蔡english") %>%
group_by(text_segment) %>%
filter(n() >= 10) %>%
pairwise_cor(text_segment, sentence_id, sort = TRUE)
word_cors_tsai %>% filter(row_number() %% 2 == 0)
## # A tibble: 23,653 × 3
## item1 item2 correlation
## <chr> <chr> <dbl>
## 1 大會 主席 0.798
## 2 國人 同胞 0.764
## 3 院長 主席 0.760
## 4 主席 院長 0.760
## 5 主席 現場 0.731
## 6 貴賓 網路 0.692
## 7 現場 貴賓 0.666
## 8 網路 主席 0.663
## 9 主席 網路 0.663
## 10 服務 增加 0.663
## # ℹ 23,643 more rows
word_cors_ma <- df_speech_seg_unnest %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
filter(president == "馬英九") %>%
group_by(text_segment) %>%
filter(n() >= 10) %>%
pairwise_cor(text_segment, sentence_id, sort = TRUE)
word_cors_ma %>% filter(row_number() %% 2 == 0)
## # A tibble: 17,391 × 3
## item1 item2 correlation
## <chr> <chr> <dbl>
## 1 副總統 院長 0.893
## 2 院長 閣下 0.865
## 3 各位 鄉親 0.848
## 4 維持 現狀 0.802
## 5 副總統 閣下 0.772
## 6 九二 共識 0.757
## 7 大會 閣下 0.641
## 8 簽署 協議 0.626
## 9 共和國 閣下 0.613
## 10 鄉親 父老 0.593
## # ℹ 17,381 more rows
word_cors_chen <- df_speech_seg_unnest %>%
filter(!text_POS %in% c("Puncuation")) %>%
filter(str_length(text_segment) > 1) %>%
filter(president == "陳水扁") %>%
group_by(text_segment) %>%
filter(n() >= 10) %>%
pairwise_cor(text_segment, sentence_id, sort = TRUE)
word_cors_chen %>% filter(row_number() %% 2 == 0)
## # A tibble: 15,931 × 3
## item1 item2 correlation
## <chr> <chr> <dbl>
## 1 中華 共和國 0.873
## 2 公民 投票 0.812
## 3 同胞 國人 0.783
## 4 政黨 輪替 0.672
## 5 各位 伙伴 0.671
## 6 各位 貴賓 0.634
## 7 貴賓 伙伴 0.631
## 8 正義 公平 0.588
## 9 自由 人權 0.535
## 10 體制 憲政 0.502
## # ℹ 15,921 more rows